package com.study.crypto.signer.ofd;

import com.study.crypto.signer.PKCS7GmSigner;
import org.apache.commons.io.IOUtils;
import org.apache.http.util.Asserts;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.gm.GMObjectIdentifiers;
import org.bouncycastle.asn1.x509.Certificate;
import org.bouncycastle.crypto.CryptoException;
import org.bouncycastle.crypto.digests.SM3Digest;
import org.bouncycastle.jcajce.provider.digest.SM3;
import org.ofdrw.core.signatures.SigType;
import org.ofdrw.sign.ExtendSignatureContainer;

import java.io.IOException;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.security.PrivateKey;
import java.security.SignatureException;
import java.security.cert.CRL;

/**
 * 符合 《GB/T 35275-2017 SM2密码算法加密签名消息语法规范》
 * @author Songjin
 * @since 2020-11-20 15:54
 */
public class OfdPKCS7GmContainer implements ExtendSignatureContainer {
    
    private final Certificate certificate;
    private final PrivateKey privateKey;
    private final CRL[] crls;
    private final boolean containContent;
    
    public OfdPKCS7GmContainer(Certificate certificate, PrivateKey privateKey, CRL[] crls, boolean containContent) {
        this.certificate = certificate;
        this.privateKey = privateKey;
        this.crls = crls;
        this.containContent = containContent;
    }
    
    @Override
    public MessageDigest getDigestFnc() {
        return new SM3.Digest();
    }
    
    @Override
    public ASN1ObjectIdentifier getSignAlgOID() {
        return GMObjectIdentifiers.sm2sign_with_sm3;
    }
    
    @Override
    public byte[] sign(InputStream inData, String propertyInfo) throws IOException, GeneralSecurityException {
        try {
            Asserts.notNull(privateKey, "privateKey");
            Asserts.notNull(certificate, "certificate");
            byte[] plaintext = IOUtils.toByteArray(inData);
            byte[] hash = new byte[32];
            SM3Digest digest = new SM3Digest();
            digest.update(plaintext, 0, plaintext.length);
            digest.doFinal(hash, 0);
            
            PKCS7GmSigner signer;
            if (containContent) {
                signer = new PKCS7GmSigner(certificate, crls, hash);
            } else {
                signer = new PKCS7GmSigner(certificate, crls, null);
            }
            return signer.sign(hash, privateKey);
        } catch (CryptoException e) {
            throw new SignatureException("SM2消息签名异常", e);
        }
    }
    
    @Override
    public byte[] getSeal() {
        throw new IllegalArgumentException("不支持的方法");
    }
    
    @Override
    public SigType getSignType() {
        return SigType.Sign;
    }
}
